Skip to content

fix: handle counterparty channel closes#806

Merged
ovitrif merged 32 commits intofix/reimport-channel-monitorfrom
fix/channel-close-ui
Mar 3, 2026
Merged

fix: handle counterparty channel closes#806
ovitrif merged 32 commits intofix/reimport-channel-monitorfrom
fix/channel-close-ui

Conversation

@jvsena42
Copy link
Member

@jvsena42 jvsena42 commented Feb 25, 2026

Closes #802 (comment)

This PR:

  1. Adds counterparty channel close detection and user notification via a "Connection Closed" sheet
  2. Creates transfer records for counterparty-initiated channel closes (force and cooperative)
  3. Improves syncTransferStates to handle batched force-close sweeps correctly

Description

  • Classifies ClosureReason variants to detect counterparty-initiated closes (force close vs cooperative)
  • Creates a transfer when a counterparty closes a channel, looking up the channel balance from lightning balances or closed channel records
  • Shows a "Connection Closed" bottom sheet to inform the user
  • Adds PendingSweepBalance extension functions for extracting channel IDs and spending txids
  • Improves force close settlement logic in syncTransferStates: checks on-chain activity for the channel, falls back to pending sweep status, and handles batched sweeps where LDK links a single transaction to multiple channels
  • Adds helper methods in CoreService.ActivityService for querying on-chain activity by channel or txid
  • Adds unit tests for the new force close sync scenarios

Preview

coop-close.webm
counterparty-coop-close.webm
conterparty-force-close.webm
force-close-settle.webm

The timestamps didn't change because of a bug caused by fast mining 146 blocks DataException: confirm_timestamp must be greater than or equal to timestamp

QA Notes

for counterparty closing use the slack command /regtest-ln-close-channel <fundingTx:vout> [force]

  1. Counterparty force close detection

    • In regtest, open a channel with the LSP
    • Force close the channel from the LSP side
    • Mine 1 block
    • Verify the "Connection Closed" sheet appears
    • Mine 146 blocks
    • Verify a transfer banner appears on the savings screen tracking the sweep
  2. ** Counterparty cooperative close detection**

    • Trigger a cooperative close from the counterparty
    • Verify the transfer is created
    • Verify the spending balance is imediately subtracted
  3. Cooperative close detection

    • Transfer to spending flow
    • Verify the transfer is created
    • Verify the spending balance is imediately subtracted

@jvsena42 jvsena42 self-assigned this Feb 25, 2026
@jvsena42 jvsena42 changed the base branch from master to fix/reimport-channel-monitor February 25, 2026 18:29
@jvsena42 jvsena42 marked this pull request as ready for review February 26, 2026 11:32
@jvsena42 jvsena42 requested a review from ovitrif February 26, 2026 11:42
@pwltr pwltr self-requested a review February 26, 2026 14:06
@pwltr
Copy link
Contributor

pwltr commented Feb 26, 2026

The easier way of triggering a force-close on Blocktank side is simulating #802 bug

Can also use the staging bot /regtest-ln-close-channel <fundingTx:vout> [force]

@pwltr

This comment was marked as resolved.

@pwltr

This comment was marked as resolved.

@jvsena42 jvsena42 marked this pull request as draft February 26, 2026 17:44
@jvsena42 jvsena42 marked this pull request as ready for review February 27, 2026 16:34
@jvsena42
Copy link
Member Author

Copy link
Contributor

@pwltr pwltr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tested, LGTM.

I noticed an issue with total balance but saw that was already tracked in #808.

Leaving code review to @ovitrif

Copy link
Collaborator

@ovitrif ovitrif left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code changes LGTM, well structured, clean, and nicely tested 👏🏻

None of my review comments warrant changes in this PR.

Going to merge this into parent PR and run one testing round there.

walletRepo.balanceState,
transferRepo.forceCloseRemainingDuration,
) { balanceState, remainingDuration ->
val defaultTitle = context.getString(R.string.lightning__transfer_in_progress)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: can be lifted out of combine (before it) so it doesn't have to recompute with each collection.

although I think there is close to zero perf impact, the resource values are probably cached/ lazy-loaded.

) { balanceState, remainingDuration ->
val defaultTitle = context.getString(R.string.lightning__transfer_in_progress)
val savingsTitle = remainingDuration?.let {
context.getString(R.string.lightning__transfer_ready_in, it)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

noop: nice, maybe we should slowly transition to the builtin parametrization standards, makes our agent's job easier.

}

private suspend fun createTransferForCounterpartyClose(channelId: String, isForceClose: Boolean) {
val transferType = if (isForceClose) TransferType.FORCE_CLOSE else TransferType.COOP_CLOSE
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: could've been the type of the 2nd param in the tuple/pair returned by classifyClosureReason, ie: Pair<Boolean, TransferType>

}

// TODO Temporary fix while these schemes can't be decoded https://github.com/synonymdev/bitkit-core/issues/70
@Suppress("SpellCheckingInspection")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: my IDE was highlighting the string value passed to the regex ctors from the replace chain 🥲

@ovitrif ovitrif merged commit a401035 into fix/reimport-channel-monitor Mar 3, 2026
22 checks passed
@ovitrif ovitrif deleted the fix/channel-close-ui branch March 3, 2026 13:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants